package com.pro.framework.api.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.pro.framework.api.model.IModel;
import com.pro.framework.api.model.IModelHasUpdate;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class CollUtils {

    /**
     * 默认空数据组 只读
     */
    public static <T extends List<?>> T nullEmpty(T list) {
        //noinspection unchecked
        return null == list ? (T) Collections.EMPTY_LIST : list;
    }

    /**
     * 提取集合中指定属性形成 Set
     *
     * @param list   原始集合
     * @param keyFun 属性函数
     * @return 属性值集合（去重）
     */
    public static <PROP, T> Set<PROP> propSet(Collection<T> list, Function<T, PROP> keyFun) {
        return list.stream().map(keyFun).collect(Collectors.toSet());
    }

    /**
     * 将集合转换为 Map，key 由 keyFun 决定，value 为元素自身。key 不可重复。
     *
     * @param list   原始集合
     * @param keyFun key 提取函数
     * @return 转换后的 Map
     */
    public static <KEY, T> Map<KEY, T> listToMap(Collection<T> list, Function<T, KEY> keyFun) {
        return listToMap(list, keyFun, o -> o);
    }

    /**
     * 将集合转换为 Map，key 和 value 自定义提取函数，key 不可重复，value 允许为 null。
     *
     * @param list     原始集合
     * @param keyFun   key 提取函数
     * @param valueFun value 提取函数
     * @return 转换后的 Map
     */
    public static <KEY, VALUE, T> Map<KEY, VALUE> listToMap(Collection<T> list, Function<T, KEY> keyFun, Function<T, VALUE> valueFun) {
        Map<KEY, VALUE> map = new LinkedHashMap<>();
        for (T item : list) {
            KEY key = keyFun.apply(item);
            VALUE value = valueFun.apply(item);

            // 检查 key 是否重复
            if (map.containsKey(key)) {
                VALUE existingValue = map.get(key);
                throw new RuntimeException("Key不能重复 | key=" + key +
                        ", 已存在值=\n" + JSONUtil.toJsonStr(existingValue) +
                        ", 新值=\n" + JSONUtil.toJsonStr(value));
            }

            map.put(key, value); // 这里 value 为 null 也没问题
        }
        return map;
    }


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Person {
        private Integer id;
        private String name;
        private String phoneNumber; // 这个字段可能为 null
//        private Integer age;
//        private String email;
    }

    public static void main(String[] args) {
        List<Person> personList = Arrays.asList(
                new Person(1, "Alice", null), // phoneNumber 为 null
                new Person(2, "Bob", "123-4567")
        );

// 当处理第一个元素时，valueFun (Person::getPhoneNumber) 返回 null，
// 这会立即导致 NullPointerException
        Map<Integer, String> idToPhoneMap = listToMap(
                personList,
                Person::getId,
                Person::getPhoneNumber // 这个函数可能返回 null
        );
        System.out.println(JSONUtil.toJsonStr(idToPhoneMap));
    }

    /**
     * 将 Map<IModel> 类型的值扁平化，例如 key.subKey=value。
     *
     * @param map 原始 Map
     * @return 扁平化后的 Map
     */
    public static Map<String, Object> flatMap(Map<String, ?> map) {
        if (map == null) return null;

        Map<String, Object> result = new LinkedHashMap<>();
        map.forEach((key, val) -> {
            if (val instanceof IModel model) {
                BeanUtil.beanToMap(model).forEach((subKey, subValue) ->
                        result.put(key + "." + subKey, subValue)
                );
            } else {
                result.put(key, val);
            }
        });
        return result;
    }

    /**
     * 宽容转换为 Map：key/value 允许为空，key 重复时后者覆盖前者。
     */
    public static <KEY, T> Map<KEY, T> listToMapAllRight(Collection<T> list, Function<T, KEY> keySupplier) {
        return listToMapAllRight(list, keySupplier, o -> o);
    }

    /**
     * 宽容转换为 Map：key/value 允许为空，key 重复时后者覆盖前者。
     */
    public static <KEY, T> Map<KEY, T> listToMapAllRight(Collection<T> list, Function<T, KEY> keySupplier, List<T> ignoreList) {
        Map<KEY, T> map = new LinkedHashMap<>();
        for (T item : list) {
            KEY key = keySupplier.apply(item);
            if (map.containsKey(key)) {
                ignoreList.add(map.get(key));
            }
            map.put(key, item);
        }
        return map;
    }

    /**
     * 宽容转换为 Map：key/value 允许为空，key 重复时后者覆盖前者。
     */
    public static <KEY, VALUE, T> Map<KEY, VALUE> listToMapAllRight(Collection<T> list, Function<T, KEY> keySupplier, Function<T, VALUE> valueSupplier) {
        Map<KEY, VALUE> map = new LinkedHashMap<>();
        for (T item : list) {
            KEY key = keySupplier.apply(item);
            if (map.containsKey(key)) {

            }
            map.put(key, valueSupplier.apply(item));
        }
        return map;
    }

    /**
     * 宽容转换为 Map：key/value 允许为空，key 重复时保留第一次。
     */
    public static <KEY, VALUE, T> Map<KEY, VALUE> listToMapAllRightFirst(Collection<T> list, Function<T, KEY> keySupplier, Function<T, VALUE> valueSupplier) {
        Map<KEY, VALUE> map = new LinkedHashMap<>();
        for (T item : list) {
            map.putIfAbsent(keySupplier.apply(item), valueSupplier.apply(item));
        }
        return map;
    }

    /**
     * 将列表按指定大小分批，并对每一批执行函数并收集结果。
     */
    public static <T, V> List<V> execute(List<T> list, int batchSize, Function<List<T>, V> function) {
        List<V> result = new ArrayList<>();
        for (int i = 0; i < list.size(); i += batchSize) {
            int end = Math.min(i + batchSize, list.size());
            result.add(function.apply(list.subList(i, end)));
        }
        return result;
    }

    /**
     * 将列表按默认每 400 个分批，执行函数并收集结果。
     */
    public static <T, V> List<V> execute(List<T> list, Function<List<T>, V> function) {
        return execute(list, 400, function);
    }

    /**
     * 将列表按指定大小分批，对每一批执行操作（不收集返回值）。
     */
    public static <T> void execute(List<T> list, int batchSize, java.util.function.Consumer<List<T>> consumer) {
        for (int i = 0; i < list.size(); i += batchSize) {
            int end = Math.min(i + batchSize, list.size());
            consumer.accept(list.subList(i, end));
        }
    }

    /**
     * 将列表按默认每 400 个分批，对每一批执行操作（不收集返回值）。
     */
    public static <T> void execute(List<T> list, java.util.function.Consumer<List<T>> consumer) {
        execute(list, 400, consumer);
    }

    /**
     * 计算 BigDecimal 值总和。
     */
    public static <T> BigDecimal sum(List<T> list, Function<T, BigDecimal> amountFun) {
        return list.stream()
                .map(amountFun)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 计算 Integer 值总和。
     */
    public static <T> Integer sumInteger(List<T> list, Function<T, Integer> amountFun) {
        return list.stream()
                .map(amountFun)
                .filter(Objects::nonNull)
                .reduce(0, Integer::sum);
    }

    /**
     * 将 Map<K, List<V>> 转换为 Map<K, V>（取第一个元素）。
     */
    public static <K, V> Map<K, V> toFirstElementMap(Map<K, List<V>> map) {
        if (map == null) return Collections.emptyMap();

        return map.entrySet().stream()
                .filter(e -> e.getValue() != null && !e.getValue().isEmpty())
                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
    }

    /**
     * 根据 key 函数对列表分组，并对每组执行转换函数。
     */
    public static <T, KEY, VALUE> LinkedHashMap<KEY, VALUE> groupBy(Collection<T> list, Function<T, KEY> keyFun, Function<List<T>, VALUE> valueFun) {
        Map<KEY, List<T>> grouped = groupBy(list, keyFun);
        LinkedHashMap<KEY, VALUE> result = new LinkedHashMap<>();

        for (Map.Entry<KEY, List<T>> entry : grouped.entrySet()) {
            VALUE value = valueFun.apply(entry.getValue());
            result.put(entry.getKey(), value); // 这里允许value为null
        }
        return result;
    }

    /**
     * 根据 key 函数对列表分组。
     */
    public static <T, KEY> Map<KEY, List<T>> groupBy(Collection<T> list, Function<T, KEY> keyFun) {
        Map<KEY, List<T>> result = new LinkedHashMap<>();
        for (T element : list) {
            KEY key = keyFun.apply(element);
            result.computeIfAbsent(key, k -> new ArrayList<>()).add(element);
        }
        return result;
    }

    /**
     * 将列表按指定大小分割为多个子列表（二维列表）。
     */
    public static <T> List<List<T>> partitionList(List<T> list, int size) {
        List<List<T>> result = new ArrayList<>();
        int total = list.size();
        for (int i = 0; i < total; i += size) {
            int end = Math.min(i + size, total);
            result.add(list.subList(i, end));
        }
        return result;
    }

    public static <T1, T2, R> List<R> forEach(List<T1> list1, List<T2> list2, BiFunction<T1, T2, R> function) {
        AssertUtil.isTrue(list1.size() == list2.size(), "异常数据");
        return IntStream.range(0, list1.size())
                .mapToObj(i -> function.apply(list1.get(i), list2.get(i)))
                .toList(); // Java 16+，返回不可变 List；可改成 collect(Collectors.toList()) 返回可变 List
    }

    public static <T1, T2> void forEach(List<T1> list1, List<T2> list2, BiConsumer<T1, T2> function) {
        AssertUtil.isTrue(list1.size() == list2.size(), "异常数据");
        IntStream.range(0, list1.size())
                .forEach(i -> function.accept(list1.get(i), list2.get(i)));
    }


}
